﻿/*
-----------------------------------------------------------------------------
This source file is part of Cell Cloud.

Copyright (c) 2009-2012 Cell Cloud Team - cellcloudproject@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "CellStableHeaders.h"
#include "CellPrimitiveSerializer.h"
#include "CellPrimitive.h"
#include "CellDialect.h"
#include "CellDialectEnumerator.h"
#include "CellStringConverter.h"

namespace cell
{

const PrimitiveSerializer::Version PrimitiveSerializer::VERSION(1, 0);

#define TOKEN_OPEN_BRACKET    '['
#define TOKEN_CLOSE_BRACKET   ']'
#define TOKEN_OPEN_BRACE      '{'
#define TOKEN_CLOSE_BRACE     '}'
#define TOKEN_POINT           '.'
#define TOKEN_OPERATE_ASSIGN  '='
#define TOKEN_OPERATE_DECLARE ':'
#define TOKEN_AT              '@'

#define PARSE_PHASE_UNKNOWN 0
#define PARSE_PHASE_TYPE    1
#define PARSE_PHASE_LITERAL 2
#define PARSE_PHASE_VALUE   3
#define PARSE_PHASE_MAJOR   4
#define PARSE_PHASE_MINOR   5
#define PARSE_PHASE_STUFF   6
#define PARSE_PHASE_DIALECT 7

#define LITERALBASE_STRING  "string"
#define LITERALBASE_INT     "int"
#define LITERALBASE_UINT    "uint"
#define LITERALBASE_LONG    "long"
#define LITERALBASE_ULONG   "ulong"
#define LITERALBASE_BOOL    "bool"
#define LITERALBASE_UNKNOWN "unknown"

#define STUFFTYPE_SUBJECT     "sub"
#define STUFFTYPE_PREDICATE   "pre"
#define STUFFTYPE_OBJECTIVE   "obj"
#define STUFFTYPE_ADVERBIAL   "adv"
#define STUFFTYPE_ATTRIBUTIVE "att"
#define STUFFTYPE_COMPLEMENT  "com"
#define STUFFTYPE_UNKNOWN     "unknown"

//-----------------------------------------------------------------------
PrimitiveSerializer::PrimitiveSerializer(const Version& version)
	: Serializer(Serializer::CAP_WRITE | Serializer::CAP_READ)
	, mVersion(version)
{
	mFactory = CELL_NEW PrimitiveSerializerSubstanceFactory();
}
//-----------------------------------------------------------------------
PrimitiveSerializer::~PrimitiveSerializer(void)
{
	CELL_DELETE mFactory;
}
//-----------------------------------------------------------------------
bool PrimitiveSerializer::write(SerializerStream& out, Serializable* in)
{
	/*
	原语序列化格式：
	[version]{sutff}...{stuff}[dialect@tracker]
	示例：
	[01.00]{sub=cloud:string}{pre=add:string}[FileReader@Lynx]
	*/

	// 序列化版本
	serializeVersion(out, mVersion);

	PrimitiveSerializerSubstance* substance = mFactory->create(mVersion);
	if (substance == NULL)
	{
		// 没有匹配的版本
		return false;
	}

	Primitive* primitive = dynamic_cast<Primitive*>(in);
	substance->serialize(out, primitive);

	return true;
}
//-----------------------------------------------------------------------
bool PrimitiveSerializer::read(Serializable* out, SerializerStream& in)
{
	// 反序列化版本
	Version destVersion;
	deserializeVersion(destVersion, in);

	// 判断版本是否兼容
	if (false == checkCompatibility(destVersion))
	{
		return false;
	}

	// 使用指定的版本
	PrimitiveSerializerSubstance* substance = mFactory->create(destVersion);
	if (substance == NULL)
	{
		// 没有匹配的版本
		return false;
	}

	Primitive* primitive = dynamic_cast<Primitive*>(out);
	substance->deserialize(primitive, in);

	return true;
}
//-----------------------------------------------------------------------
void PrimitiveSerializer::serializeVersion(SerializerStream& strm, const Version& version) const
{
	/**
	序列化格式：
	[major.minor]
	major - 2 bytes
	minor - 2 bytes
	*/

	String major = StringConverter::toString(version.mMajor, 2, '0');
	String minor = StringConverter::toString(version.mMinor, 2, '0');
	strm << TOKEN_OPEN_BRACKET;
	strm << major;
	strm << TOKEN_POINT;
	strm << minor;
	strm << TOKEN_CLOSE_BRACKET;
}
//-----------------------------------------------------------------------
void PrimitiveSerializer::deserializeVersion(Version& version,
	SerializerStream& strm)
{
	char strmbuf[8] = {0x0};
	strm.read(strmbuf, 7);

	int phase = PARSE_PHASE_UNKNOWN;
	String buf;
	for (int i = 0; i < 7; ++i)
	{
		char c = strmbuf[i];
		switch (c)
		{
		case TOKEN_OPEN_BRACKET:
			// 开始分析主版本号
			buf.clear();
			c = strmbuf[++i];
			phase = PARSE_PHASE_MAJOR;
			break;
		case TOKEN_POINT:
			// 结束分析主版本号
			version.mMajor = StringConverter::parseInt(buf);
			// 开始分析副版本号
			buf.clear();
			c = strmbuf[++i];
			phase = PARSE_PHASE_MINOR;
			break;
		case TOKEN_CLOSE_BRACKET:
			// 结束分析副版本号
			version.mMinor = StringConverter::parseInt(buf);
			break;
		default:
			break;
		}

		switch (phase)
		{
		case PARSE_PHASE_MAJOR:
			buf += c;
			break;
		case PARSE_PHASE_MINOR:
			buf += c;
			break;
		default:
			break;
		}
	}
}
//-----------------------------------------------------------------------
bool PrimitiveSerializer::checkCompatibility(const Version& version)
{
	if (mVersion.mMajor < version.mMajor)
		return false;
	if (mVersion.mMinor < version.mMinor)
		return false;
	return true;
}


//-----------------------------------------------------------------------
PrimitiveSerializer::Version::Version(void)
	: mMajor(0)
	, mMinor(0)
{
}
//-----------------------------------------------------------------------
PrimitiveSerializer::Version::Version(const Version& other)
	: mMajor(other.mMajor)
	, mMinor(other.mMinor)
{
}
//-----------------------------------------------------------------------
PrimitiveSerializer::Version::Version(int major, int minor)
	: mMajor(major)
	, mMinor(minor)
{
}
//-----------------------------------------------------------------------
PrimitiveSerializer::Version::~Version(void)
{
}


//-----------------------------------------------------------------------
PrimitiveSerializerSubstance::PrimitiveSerializerSubstance(const PrimitiveSerializer::Version& version)
	: mVersion(version)
{
}
//-----------------------------------------------------------------------
PrimitiveSerializerSubstance::~PrimitiveSerializerSubstance(void)
{
}
//-----------------------------------------------------------------------
const String& PrimitiveSerializerSubstance::parseLiteralBase(LiteralBase literal)
{
	mLiteralBaseNameBuf.clear();
	switch (literal)
	{
	case LB_STRING:
		mLiteralBaseNameBuf = LITERALBASE_STRING;
		break;
	case LB_INT:
		mLiteralBaseNameBuf = LITERALBASE_INT;
		break;
	case LB_UINT:
		mLiteralBaseNameBuf = LITERALBASE_UINT;
		break;
	case LB_LONG:
		mLiteralBaseNameBuf = LITERALBASE_LONG;
		break;
	case LB_ULONG:
		mLiteralBaseNameBuf = LITERALBASE_ULONG;
		break;
	case LB_BOOL:
		mLiteralBaseNameBuf = LITERALBASE_BOOL;
		break;
	default:
		mLiteralBaseNameBuf = LITERALBASE_UNKNOWN;
		break;
	}
	return mLiteralBaseNameBuf;
}
//-----------------------------------------------------------------------
LiteralBase PrimitiveSerializerSubstance::parseLiteralBase(const String& base)
{
	LiteralBase literalness = LB_UNKNOWN;
	if (base == LITERALBASE_STRING)
		literalness = LB_STRING;
	else if (base == LITERALBASE_INT)
		literalness = LB_INT;
	else if (base == LITERALBASE_UINT)
		literalness = LB_UINT;
	else if (base == LITERALBASE_LONG)
		literalness = LB_LONG;
	else if (base == LITERALBASE_ULONG)
		literalness = LB_ULONG;
	else if (base == LITERALBASE_BOOL)
		literalness = LB_BOOL;
	return literalness;
}
//-----------------------------------------------------------------------
const String& PrimitiveSerializerSubstance::parseStuffType(Stuff::StuffType type)
{
	mStuffTypeNameBuf.clear();
	switch (type)
	{
	case Stuff::ST_SUBJECT:
		mStuffTypeNameBuf = STUFFTYPE_SUBJECT;
		break;
	case Stuff::ST_PREDICATE:
		mStuffTypeNameBuf = STUFFTYPE_PREDICATE;
		break;
	case Stuff::ST_OBJECTIVE:
		mStuffTypeNameBuf = STUFFTYPE_OBJECTIVE;
		break;
	case Stuff::ST_ADVERBIAL:
		mStuffTypeNameBuf = STUFFTYPE_ADVERBIAL;
		break;
	case Stuff::ST_ATTRIBUTIVE:
		mStuffTypeNameBuf = STUFFTYPE_ATTRIBUTIVE;
		break;
	case Stuff::ST_COMPLEMENT:
		mStuffTypeNameBuf = STUFFTYPE_COMPLEMENT;
		break;
	default:
		mStuffTypeNameBuf = STUFFTYPE_UNKNOWN;
		break;
	}
	return mStuffTypeNameBuf;
}
//-----------------------------------------------------------------------
Stuff::StuffType PrimitiveSerializerSubstance::parseStuffType(const String& type)
{
	Stuff::StuffType stuff = Stuff::ST_UNKNOWN;
	if (type == STUFFTYPE_SUBJECT)
		stuff = Stuff::ST_SUBJECT;
	else if (type == STUFFTYPE_PREDICATE)
		stuff = Stuff::ST_PREDICATE;
	else if (type == STUFFTYPE_OBJECTIVE)
		stuff = Stuff::ST_OBJECTIVE;
	else if (type == STUFFTYPE_ADVERBIAL)
		stuff = Stuff::ST_ADVERBIAL;
	else if (type == STUFFTYPE_ATTRIBUTIVE)
		stuff = Stuff::ST_ATTRIBUTIVE;
	else if (type == STUFFTYPE_COMPLEMENT)
		stuff = Stuff::ST_COMPLEMENT;
	return stuff;
}


//-----------------------------------------------------------------------
PrimitiveSerializer_1_0::PrimitiveSerializer_1_0(void) :
	PrimitiveSerializerSubstance(PrimitiveSerializer::Version(1,0))
{
}
//-----------------------------------------------------------------------
PrimitiveSerializer_1_0::~PrimitiveSerializer_1_0(void)
{
}
//-----------------------------------------------------------------------
void PrimitiveSerializer_1_0::serialize(SerializerStream& strm, Primitive* primitive)
{
	// 序列化各语素

	const Primitive::SubjectList* subjects = primitive->subjects();
	if (!subjects->empty())
	{
		Primitive::SubjectList::const_iterator subiter, subend = subjects->end();
		for (subiter = subjects->begin(); subiter != subend; ++subiter)
		{
			serialize(strm, Stuff::ST_SUBJECT, (*subiter).getValueAsString(), (*subiter).getLiteralBase());
		}
	}

	const Primitive::PredicateList* predicates = primitive->predicates();
	if (!predicates->empty())
	{
		Primitive::PredicateList::const_iterator preiter, preend = predicates->end();
		for (preiter = predicates->begin(); preiter != preend; ++preiter)
		{
			serialize(strm, Stuff::ST_PREDICATE,  (*preiter).getValueAsString(), (*preiter).getLiteralBase());
		}
	}

	const Primitive::ObjectiveList* objectives = primitive->objectives();
	if (!objectives->empty())
	{
		Primitive::ObjectiveList::const_iterator objiter, objend = objectives->end();
		for (objiter = objectives->begin(); objiter != objend; ++objiter)
		{
			serialize(strm, Stuff::ST_OBJECTIVE, (*objiter).getValueAsString(), (*objiter).getLiteralBase());
		}
	}

	const Primitive::AdverbialList* adverbials = primitive->adverbials();
	if (!adverbials->empty())
	{
		Primitive::AdverbialList::const_iterator adviter, advend = adverbials->end();
		for (adviter = adverbials->begin(); adviter != advend; ++adviter)
		{
			serialize(strm, Stuff::ST_ADVERBIAL, (*adviter).getValueAsString(), (*adviter).getLiteralBase());
		}
	}

	const Primitive::AttributiveList* attributives = primitive->attributives();
	if (!attributives->empty())
	{
		Primitive::AttributiveList::const_iterator attiter, attend = attributives->end();
		for (attiter = attributives->begin(); attiter != attend; ++attiter)
		{
			serialize(strm, Stuff::ST_ATTRIBUTIVE, (*attiter).getValueAsString(), (*attiter).getLiteralBase());
		}
	}

	const Primitive::ComplementList* complements = primitive->complements();
	if (!complements->empty())
	{
		Primitive::ComplementList::const_iterator comiter, comend = complements->end();
		for (comiter = complements->begin(); comiter != comend; ++comiter)
		{
			serialize(strm, Stuff::ST_COMPLEMENT, (*comiter).getValueAsString(), (*comiter).getLiteralBase());
		}
	}

	// 序列化方言

	if (NULL != primitive->getDialect())
	{
		strm << TOKEN_OPEN_BRACKET;
		strm << primitive->getDialect()->getName();
		strm << TOKEN_AT;
		strm << primitive->getDialect()->getTracker();
		strm << TOKEN_CLOSE_BRACKET;
	}
}
//-----------------------------------------------------------------------
void PrimitiveSerializer_1_0::deserialize(Primitive* primitive, SerializerStream& strm)
{
	// 跳过版本信息
	strm.seekg(7);

	size_t len = strm.length() - 7;
	char* pbuf = CELL_ALLOC_T(char, len + 1, MEMCATEGORY_GENERAL);
	memset(pbuf, 0x0, len + 1);
	strm.read(pbuf, len);

	Stuff::StuffType type = Stuff::ST_UNKNOWN;
	LiteralBase literalness = LB_UNKNOWN;
	String value;
	String valstr;
	String buf;

	char* cursor = pbuf;
	int phase = PARSE_PHASE_UNKNOWN;
	char c = *cursor;
	// 格式分析
	while (c != 0)
	{
		switch (c)
		{
		case TOKEN_OPEN_BRACE:
			c = (*(++cursor));
			buf.clear();
			phase = PARSE_PHASE_TYPE;
			break;
		case TOKEN_OPERATE_ASSIGN:
			// 解析类型
			type = parseStuffType(buf);
			c = (*(++cursor));
			buf.clear();
			phase = PARSE_PHASE_VALUE;
			break;
		case TOKEN_OPERATE_DECLARE:
			// 保存数值字符串形式
			valstr = buf;
			c = (*(++cursor));
			buf.clear();
			phase = PARSE_PHASE_LITERAL;
			break;
		case TOKEN_CLOSE_BRACE:
			// 解析值字面义
			literalness = parseLiteralBase(buf);
			value = valstr;
			// 反序列化素材
			deserialize(primitive, type, value, literalness);
			phase = PARSE_PHASE_UNKNOWN;
			break;
		case TOKEN_OPEN_BRACKET:
			if (phase == PARSE_PHASE_UNKNOWN)
			{
				// 在 UNKNOWN 阶段才能判断是否为后续数据
				// 游标定位到下一个字符
				c = (*(++cursor));
				// 清空 Buf
				buf.clear();
				phase = PARSE_PHASE_DIALECT;
			}
			break;
		case TOKEN_CLOSE_BRACKET:
			if (phase == PARSE_PHASE_DIALECT)
			{
				// 解析方言名
				deserializeDialect(primitive, buf);
				phase = PARSE_PHASE_UNKNOWN;
			}
			break;
		default:
			break;
		}

		switch (phase)
		{
		case PARSE_PHASE_TYPE:
			if (c == ' ' || c == '\t')
				break;
			buf += c;
			break;
		case PARSE_PHASE_VALUE:
			// 判断转义字符，并确认是否需要转义
			if (c == '\\')
			{
				// 出现转义符，判断下一个字符
				char nextChar = (*(++cursor));
				if (nextChar == TOKEN_OPEN_BRACE
					|| nextChar == TOKEN_CLOSE_BRACE
					|| nextChar == TOKEN_OPERATE_ASSIGN
					|| nextChar == TOKEN_OPERATE_DECLARE)
				{
					c = nextChar;
				}
				else
				{
					// 指针回退一个字符
					--cursor;
				}
			}
			buf += c;
			break;
		case PARSE_PHASE_LITERAL:
			if (c == ' ' || c == '\t')
				break;
			buf += c;
			break;
		case PARSE_PHASE_DIALECT:
			if (c == '\t' || c == '\n')
				break;
			buf += c;
			break;
		default:
			break;
		}

		cursor++;
		c = *cursor;
	}

	CELL_FREE(pbuf, MEMCATEGORY_GENERAL);
}
//-----------------------------------------------------------------------
void PrimitiveSerializer_1_0::serialize(SerializerStream& strm,
	const Stuff::StuffType type, const String& value, const LiteralBase literalness)
{
	// 序列化格式：
	// {type=value:literal}
	//
	strm << TOKEN_OPEN_BRACE;
	strm << parseStuffType(type);

	// 赋值符
	strm << TOKEN_OPERATE_ASSIGN;

	switch (literalness)
	{
	case LB_STRING:
	{
		char* revisestr = CELL_ALLOC_T(char, 4096, MEMCATEGORY_GENERAL);
		memset(revisestr, 0x0, 4096);

		revise(revisestr, value.c_str());
		strm << revisestr;

		CELL_FREE(revisestr, MEMCATEGORY_GENERAL);
		break;
	}
	case LB_INT:
		strm << StringConverter::parseInt(value);
		break;
	case LB_UINT:
		strm << StringConverter::parseUnsignedInt(value);
		break;
	case LB_LONG:
		strm << StringConverter::parseLong(value);
		break;
	case LB_ULONG:
		strm << StringConverter::parseUnsignedLong(value);
		break;
	case LB_BOOL:
		strm << StringConverter::parseBool(value);
		break;
	default:
		break;
	}

	// 类型声明
	strm << TOKEN_OPERATE_DECLARE;
	strm << parseLiteralBase(literalness);
	strm << TOKEN_CLOSE_BRACE;
}
//-----------------------------------------------------------------------
void PrimitiveSerializer_1_0::deserialize(Primitive* primitive,
	Stuff::StuffType type, const String& value, LiteralBase literal)
{
	switch (type)
	{
	case Stuff::ST_SUBJECT:
	{
		SubjectStuff stuff(value, literal);
		primitive->commit(stuff);
		break;
	}
	case Stuff::ST_PREDICATE:
	{
		PredicateStuff stuff(value, literal);
		primitive->commit(stuff);
		break;
	}
	case Stuff::ST_OBJECTIVE:
	{
		ObjectiveStuff stuff(value, literal);
		primitive->commit(stuff);
		break;
	}
	case Stuff::ST_ADVERBIAL:
	{
		AdverbialStuff stuff(value, literal);
		primitive->commit(stuff);
		break;
	}
	case Stuff::ST_ATTRIBUTIVE:
	{
		AttributiveStuff stuff(value, literal);
		primitive->commit(stuff);
		break;
	}
	case Stuff::ST_COMPLEMENT:
	{
		ComplementStuff stuff(value, literal);
		primitive->commit(stuff);
		break;
	}
	default:
		break;
	}
}
//-----------------------------------------------------------------------
void PrimitiveSerializer_1_0::deserializeDialect(Primitive* primitive, const String& data)
{
	// 解析数据串
	size_t pos = data.find_first_of(TOKEN_AT);
	String name = data.substr(0, pos);
	String tracker = data.substr(pos + 1, data.length());

	// 从工厂创建实例并设置参数
	Dialect* dialect = DialectEnumerator::getSingleton().createDialect(name, tracker);
	dialect->setTag(primitive->getOwnerTag());

	// 分析数据
	dialect->build(primitive);

	// 设置原语方言
	primitive->capture(dialect, true);
}
//-----------------------------------------------------------------------
void PrimitiveSerializer_1_0::revise(char* out, const char* in)
{
	size_t len = strlen(in);
	const char* cursor = in;
	char c;
	size_t outIndex = 0;
	for (size_t i = 0; i < len; ++i)
	{
		c = *cursor;
		switch (c)
		{
		case TOKEN_OPEN_BRACE:
		case TOKEN_CLOSE_BRACE:
		case TOKEN_OPERATE_ASSIGN:
		case TOKEN_OPERATE_DECLARE:
			out[outIndex++] = '\\';
			break;
		default:
			break;
		}

		out[outIndex++] = c;
		++cursor;
	}
}


//-----------------------------------------------------------------------
PrimitiveSerializerSubstanceFactory::PrimitiveSerializerSubstanceFactory(void)
	: mV_1_0(NULL)
{
	mV_1_0 = CELL_NEW PrimitiveSerializer_1_0();
}
//-----------------------------------------------------------------------
PrimitiveSerializerSubstanceFactory::~PrimitiveSerializerSubstanceFactory(void)
{
	if (NULL != mV_1_0)
		CELL_DELETE mV_1_0;
}
//-----------------------------------------------------------------------
PrimitiveSerializerSubstance* PrimitiveSerializerSubstanceFactory::create(const PrimitiveSerializer::Version& version)
{
	PrimitiveSerializerSubstance* substance = NULL;
	switch (version.getMajor())
	{
	case 1:
	{
		switch (version.getMinor())
		{
		case 0:
			if (NULL == mV_1_0)
				mV_1_0 = CELL_NEW PrimitiveSerializer_1_0();
			substance = mV_1_0;
			break;
		default:
			break;
		}

		break;
	}
	default:
		break;
	}
	return substance;
}
//-----------------------------------------------------------------------
void PrimitiveSerializerSubstanceFactory::destroy(PrimitiveSerializerSubstance* substance)
{
	switch (substance->mVersion.getMajor())
	{
	case 1:
	{
		switch (substance->mVersion.getMinor())
		{
		case 0:
			if (NULL != mV_1_0)
				CELL_DELETE mV_1_0;
			mV_1_0 = NULL;
			break;
		default:
			break;
		}

		break;
	}
	default:
		break;
	}
}

} // end namespace cell
